package org.fin.framework.ioc.component;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import org.fin.framework.ioc.annotation.Autowired;
import org.fin.framework.ioc.annotation.Component;
import org.fin.framework.ioc.annotation.Transactional;
import org.fin.framework.ioc.beans.BeanInterceptor;
import org.fin.framework.ioc.exception.TransactionException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.SQLException;
import java.util.Arrays;

@Component
public class TransactionBeanInterceptor implements BeanInterceptor {

  @Autowired
  private TransactionManager transactionManager;

  @Override
  public Object intercept(String beanName, Object bean) {
    Class<?> cls = bean.getClass();

    // 事务生效范围是否类级别，否则方法级别或者没有事务管理
    boolean classLevelTx = isClassLevelTransactional(cls);

    // 判断方法是否有事务管理
    boolean hasMethodTx = Arrays.stream(cls.getDeclaredMethods())
        .anyMatch(m -> m.isAnnotationPresent(Transactional.class));

    // 类级别和方法级别都没有事务管理，放行
    if (!classLevelTx && !hasMethodTx) {
      return bean;
    }


    // 有接口实现就用jdk，否则cglib
    Class<?>[] interfaces = cls.getInterfaces();
    boolean useJdk = interfaces.length != 0;
    Object porxy;

    // 使用jdk代理
    if (useJdk) {
      porxy = Proxy.newProxyInstance(
          cls.getClassLoader(),
          interfaces,
          (proxy, method, args) -> {

            // 如果不是类级别事务管理，才需要判断方法是否有事务注解
            if (!classLevelTx) {

              // 因为JDK代理的是接口，所以方法对象上面没有注解
              Method[] methods = cls.getDeclaredMethods();
              for (Method methodImpl : methods) {

                // 先获取实现类对应的方法对象
                if (methodImpl.getName().equals(method.getName())){
                  // 如果实现类和接口都没有事务注解，就直接执行返回，不进行事务管理操作
                  if (!method.isAnnotationPresent(Transactional.class) &&
                      !methodImpl.isAnnotationPresent(Transactional.class))
                  {
                    return method.invoke(bean, args);
                  }
                }
              }
            }

            return doTransaction(bean, method, args);
          }
      );
    }

    // 使用cglib代理
    else {
      porxy = Enhancer.create(
          cls,
          (MethodInterceptor) (obj, method, args, proxy) -> {
            // 如果不是类级别事务管理，才需要判断方法是否有事务注解
            if (!classLevelTx) {
              // 如果没有事务注解，直接执行返回
              if (!method.isAnnotationPresent(Transactional.class)) {
                return method.invoke(bean, args);
              }
            }
            return doTransaction(bean, method, args);
          }
      );
    }

    return porxy;
  }

  /**
   * 执行事务管理操作
   */
  private Object doTransaction(Object bean, Method method, Object[] args) throws SQLException
  {
    Object result;

    System.out.println("doTransaction");

    try{
      // 开启事务(关闭事务的自动提交)
      transactionManager.beginTransaction();

      result = method.invoke(bean, args);

      // 提交事务
      transactionManager.commit();
    }
    catch (Throwable e) {
      e.printStackTrace();
      // 回滚事务
      transactionManager.rollback();

      // 抛出异常便于上层servlet捕获
      throw new TransactionException(e);
    }

    return result;
  }

  private boolean isClassLevelTransactional(Class<?> cls) {
    while (cls != Object.class) {
      if (cls.isAnnotationPresent(Transactional.class)) {
        return true;
      }
      cls = cls.getSuperclass();
    }
    return false;
  }
}
